package net.da.client.common.component;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import net.da.client.common.config.ConfigKeyImpl;
import net.da.client.common.config.ConfigService;
import net.da.client.common.config.ConfigServiceImpl;
import net.da.client.common.config.ConfigValue;

import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;

public class ComponentDispatcherImpl implements ComponentDispatcher {
	
	private static final ComponentDispatcherImpl instance = new ComponentDispatcherImpl(); 	
	private Component currentComponent;
	private Stack componentStack;	
	
	
	private ComponentDispatcherImpl() {
		componentStack = new Stack();
	}
	
	
	public static ComponentDispatcherImpl getInstance() {		
		return instance;
	}
	
	
	public void jumpTo(String name) {
		jumpTo(name, null);		
	}
	
	public void jumpTo(String name, Map initArgs) {
		

		/*
		 * AbstractComponent component = buildComponent(name); if
		 * (currentComponent != null) { currentComponent.onHide(); }
		 * currentComponent = component; Panel componentRoot =
		 * currentComponent.getComponentRoot(); currentComponent.onShow();
		 * 
		 * RootPanel rootPanel = RootPanel.get(); rootPanel.clear();
		 * rootPanel.add(componentRoot);
		 */
				
		AbstractComponent component = buildComponent(name);
		if (currentComponent != null) {						
			currentComponent.onHide();
			currentComponent.onExit();
			hideCurrentComponent();
		}
		componentStack.clear();
		currentComponent = component;
		currentComponent.onInit(initArgs);
		currentComponent.onShow();		
		showCurrentComponent();		
	}
	
	
	private AbstractComponent buildComponent(String name) {
		
		ComponentDef componentDef = readComponentDef(name);		
		AbstractComponent component = componentDef.newComponentInstance();		
		component.setComponentDef(componentDef);		
		return component;
	}
	
	
	private ComponentDef readComponentDef(String name) {
		
		ConfigService configService = ConfigServiceImpl.getInstance();
		ConfigValue configValue = configService.readConfigValue(ConfigKeyImpl.getInstance(name));
		ComponentDef componentDef = (ComponentDef)configValue.getVlaue();		
		return componentDef;		
	}
	
	public void nestTo(String name, Map initArgs) {
		
		if (initArgs == null) {
			initArgs = new HashMap();
		}		
		AbstractComponent component = buildComponent(name);
		if (currentComponent != null) {
			currentComponent.onHide();
			componentStack.push(currentComponent);
			hideCurrentComponent();
		}
		currentComponent = component;
		currentComponent.onInit(initArgs);
		currentComponent.onShow();		
		showCurrentComponent();		
	}
	
	public void nestTo(String name) {
		nestTo(name, null);		
	}


	private void showCurrentComponent() {

		RootPanel rootPanel = RootPanel.get();
		Panel componentRoot = currentComponent.getComponentRoot();
		rootPanel.add(componentRoot);
	}

	private void hideCurrentComponent() {

		RootPanel rootPanel = RootPanel.get();
		rootPanel.clear();
	}

	
	public boolean isReturnToPriorComponentPossible() {
		return isReturnToPriorComponentPossible(1);
	}
				   
	public boolean isReturnToPriorComponentPossible(int steps) {
		int size = componentStack.size();				
		return steps <= size;
	}

	
	public void returnToPriorComponent() {
		returnToPriorComponent(1, null);
	}
	
	public void returnToPriorComponent(Map returnArgs) {
		returnToPriorComponent(1, returnArgs);
	}
		
	public void returnToPriorComponent(int steps) {
		returnToPriorComponent(steps, null);
	}

	public void returnToPriorComponent(int steps, Map returnArgs) {
		
		if (returnArgs == null) {
			returnArgs = new HashMap();
		}		
		if (isReturnToPriorComponentPossible(steps)){
			if (currentComponent != null) {
				currentComponent.onHide();
				currentComponent.onExit();
				hideCurrentComponent();
			} 
			for (int i = 0; i < steps; i++) {
				currentComponent = (AbstractComponent)componentStack.pop();				
			}						
			currentComponent.onReturn(returnArgs);
			currentComponent.onShow();		
			showCurrentComponent();
		}	else {
			currentComponent.onInvalidReturn();			
		}		
	}


	public String[] getNestedComponentNames() {
		
		String[] names = new String[componentStack.size()];
		for (int i = 0; i < names.length; i++) {
			AbstractComponent component = (AbstractComponent)componentStack.get(i);
			names[i] = component.getComponentDef().getName();
		}
		return names; 
	}



}
